
#include <BPainter>
#include <BScrollBar>
#include <BMouseEvent>

#include <BScrollArea>
#include "member_BScrollArea.h"

using namespace BWE;

#define member					(*(member_BScrollArea*)_ptr)
#define member_allocate()		_ptr = new member_BScrollArea(this)
#define member_release()		delete (member_BScrollArea*)_ptr

BScrollArea::BScrollArea(BWidget* parent) : BWidget(parent)
{
	member_allocate();
	this->setPerch(Part_Right, 16);
	this->setPerch(Part_Bottom, 16);
	BScrollBar* vScrollBar = new BScrollBar();
	this->setVerticalScrollBar(vScrollBar);
	BScrollBar* hScrollBar = new BScrollBar();
	this->setHorizontalScrollBar(hScrollBar);

}
BScrollArea::~BScrollArea()
{
	member_release();
}

void BScrollArea::setVerticalScrollBarPolicy(ScrollBarPolicy scrollBarPolicy)
{
	if (member.vScrollBarPolicy != scrollBarPolicy)
	{
		member.vScrollBarPolicy = scrollBarPolicy;
		this->fresh();
	}
}
ScrollBarPolicy BScrollArea::verticalScrollBarPolicy() const
{
	return member.vScrollBarPolicy;
}

void BScrollArea::setHorizontalScrollBarPolicy(ScrollBarPolicy scrollBarPolicy)
{
	if (member.hScrollBarPolicy != scrollBarPolicy)
	{
		member.hScrollBarPolicy = scrollBarPolicy;
		this->fresh();
	}
}
ScrollBarPolicy BScrollArea::horizontalScrollBarPolicy() const
{
	return member.hScrollBarPolicy;
}

void BScrollArea::setVerticalScrollBar(BScrollBar* scrollBar)
{
	if (member.vScrollBar != scrollBar)
	{
		if (member.vScrollBar)
		{
			member.disconnect(member.vScrollBar);
			this->removeChild(member.vScrollBar);
		}
		member.vScrollBar = scrollBar;
		if (member.vScrollBar)
		{
			member.vstep = member.vScrollBar->step();
			member.vScrollBar->setParent(this);
			member.vScrollBar->setOrientation(Orientation_Vertical);
			member.connect(member.vScrollBar, Signal_Scrolling, &member_BScrollArea::procVerticalScrolling);
		}
	}
}
const BScrollBar* BScrollArea::verticalScrollBar() const
{
	return member.vScrollBar;
}
BScrollBar* BScrollArea::verticalScrollBar()
{
	return member.vScrollBar;
}

void BScrollArea::setHorizontalScrollBar(BScrollBar* scrollBar)
{
	if (member.hScrollBar != scrollBar)
	{
		if (member.hScrollBar)
		{
			member.disconnect(member.hScrollBar);
			this->removeChild(member.hScrollBar);
		}
		member.hScrollBar = scrollBar;
		if (member.hScrollBar)
		{
			member.hstep = member.hScrollBar->step();
			scrollBar->setParent(this);
			scrollBar->setOrientation(Orientation_Horizontal);
			member.connect(member.hScrollBar, Signal_Scrolling, &member_BScrollArea::procHorizontalScrolling);
		}
	}
}
const BScrollBar* BScrollArea::horizontalScrollBar() const
{
	return member.hScrollBar;
}
BScrollBar* BScrollArea::horizontalScrollBar()
{
	return member.hScrollBar;
}

void BScrollArea::setArea(int x, int y, int width, int height)
{
	setArea(BRect(x, y, width, height));
}
void BScrollArea::setArea(const BRect& area)
{
	BRect temp = area;
	if (area.width() < 0)
		temp.setWidth(0);
	if (area.height() < 0)
		temp.setHeight(0);
	int xoffset = 0;
	int yoffset = 0;
	BRect crect = this->clientRect();
	if (area.left() > crect.left())
		xoffset += crect.left() - area.left();
	if (area.top() > crect.top())
		yoffset += crect.top() - area.top();
	if (area.width() <= crect.width())
	{
		if (area.left() < crect.left())
			xoffset += crect.left() - area.left();
		if (area.right() > crect.right())
			xoffset += crect.right() - area.right();
	}
	if (area.height() <= crect.height())
	{
		if (area.top() < crect.top())
			yoffset += crect.top() - area.top();
		if (area.bottom() > crect.bottom())
			yoffset += crect.bottom() - area.bottom();
	}
	temp += BPoint(xoffset, yoffset);
	if (member.area != temp)
	{
		member.area = temp;
		member.adjustScrollBar();
		this->scrollArea();
	}
}
const BRect& BScrollArea::area() const
{
	return member.area;
}

BPoint BScrollArea::offset() const
{
	return member.area.pos() - this->clientRect().pos();
}

void BScrollArea::resizeEvent(const BEvent& event)
{
	member.adjustScrollBar();
}

void BScrollArea::mouseWheelEvent(const BMouseEvent& mouseEvent)
{
	int wheel = mouseEvent.wheel();
	if (member.vScrollBar && member.vScrollBar->visible())
	{
		int value = member.vScrollBar->value();
		int step = member.vScrollBar->step();
		member.vScrollBar->setValue(value - step * wheel);
		member.vScrollBar->emit(Signal_Scrolling, member.vScrollBar->value());
	}
}
